﻿using System;
using System.Net;
using System.Threading;
using CoreLibrary;
using CoreLibrary.Collection;
using CoreLibrary.Service;
using Entities.Enumeration;
using Modules.Tracking.API;
using NLog;

namespace Modules.Tracking {

    public class ShipmentService : ServiceBase, IShipmentService{

        public int MaxAttempts { get; set; }
        public readonly ReadWriteDictionary<Courier,IShipmentAPI>
            Api = new ReadWriteDictionary<Courier, IShipmentAPI>();

        public ShipmentService() {
            MaxAttempts = 3;
        }

        protected override void OnInit() {
            Asserts.NotNull(Api, "Api can not be null.");
        }

        protected override void OnStart() {
             Api.Put(Courier.OneExpress, new AuOneExpressAPI());
             Api.Put(Courier.EverFast,   new EverFastAPI());
        }
        
        protected override void OnStop() {
             Api.Clear();
        }

        protected override void OnDestroy() {
            Stop();
        }

        public TrackResult Track(TrackRequest request) {
            for (var attempts = 1; attempts <= MaxAttempts; attempts++) {
                try {
                    Thread.Sleep(100);
                    var shipmentApi = Api.Get(Courier.GetInstance(request.CourierId));
                    if (shipmentApi == null) {
                        throw new Exception(Courier.GetName(request.CourierId) +" 并没有被支持.");
                    }

                    return new TrackResult {
                        Succeed      = true,
                        Attempts     = attempts,
                        ErrorMessage = string.Empty,
                        Data         = shipmentApi.Track(request.TrackId),
                        TrackId      = request.TrackId  
                    };

                } 
                catch (WebException exception) {
                    string errorMessage;
                    if (exception.Status == WebExceptionStatus.ProtocolError) {
                        var response = (HttpWebResponse)exception.Response;
                        errorMessage = "Track package failed, Error Code: " + 
                                        response.StatusCode + 
                                        " Error Message: "  + IOUtil.ReadStringAndClose(response.GetResponseStream());
                        LogManager.GetCurrentClassLogger().ErrorException(errorMessage, exception);
                    } 
                    else {
                        errorMessage = "Track package failed, Status Code: " + 
                                       exception.Status  +
                                       "ErrorMessage : " + Util.GetString(exception.Message);
                        LogManager.GetCurrentClassLogger().ErrorException(errorMessage, exception);
                    }

                    if (attempts >= 3) {
                        return new TrackResult {
                            Succeed      = false,
                            Attempts     = attempts,
                            ErrorMessage = Util.GetString(errorMessage),
                            Data         = string.Empty,
                            TrackId      = request.TrackId
                        };
                    }

                } catch (Exception exception) {
                    LogManager.GetCurrentClassLogger().ErrorException("Track package failed, Error Message: " +
                        exception.Message, 
                        exception
                    );
                    if (attempts >= 3) {
                        return new TrackResult {
                            Succeed      = false,
                            Attempts     = attempts,
                            ErrorMessage = exception.Message,
                            Data         = string.Empty,
                            TrackId      = request.TrackId
                        };
                    }
                }
            }

            return new TrackResult {
                Succeed      = false,
                Attempts     = MaxAttempts,
                ErrorMessage = "Unknow Error, Server may not be available.",
                Data         = string.Empty,
                TrackId      = request.TrackId
            };
        }

        
    }
}